package com.java110.acct.payment.adapt.pxlc.utils;


import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

public class DigestMD5Util {
	private static final Logger log = LoggerFactory.getLogger(DigestMD5Util.class);
	/**
	 * 生成签名
	 *
	 * @return
	 * @throws Exception
	 */
	public static String md5Sign(String jsonStr, String keyStr,KeyType keyType) throws Exception {
		Map<String, Object> mapTemp = new HashMap<String, Object>();
		JSONObject jsonObject = JSONObject.fromObject(jsonStr);
		Iterator<?> it = jsonObject.keys();
		while (it.hasNext()) {
			String key = String.valueOf(it.next());
			Object value = jsonObject.get(key);
			if (!key.equals("sign") && !ToolsUtil.isBlank(value)) {
				if (value instanceof JSONArray) {
					JSONArray jsonArray = createSortArray(JSONArray.fromObject(value));
					mapTemp.put(key, jsonArray);
				} else if(value instanceof JSONObject){
					JSONObject jsonObj=createSortObject(JSONObject.fromObject(value));
					mapTemp.put(key, jsonObj);
				}else {
					mapTemp.put(key, value);
				}
			}
		}
		// 字典序排序
		String strValue = genString(mapTemp, keyStr,keyType).toString();
		strValue=strValue.replace("\\", "\\\\");
		log.info("replace before strValue:{}", strValue);
		strValue=strValue.replace("\\\"null\\\"", "null");
		log.info("replace after strValue:{}", strValue);
		// MD5加密
		String strValidateSign = calcValidateSign(strValue);
		if (strValidateSign == null) {
			return null;
		}
		return strValidateSign;
	}

	/**
	 * json数组排序
	 *
	 * @param jsonArray
	 * @return
	 */
	private static JSONArray createSortArray(JSONArray jsonArray) {
		List<String> jsonList = new ArrayList<String>();
		Map<String, Object> mapTemp = new TreeMap<String, Object>();
		for (int i = 0; i < jsonArray.size(); i++) {
			JSONObject jsonObject = jsonArray.getJSONObject(i);
			Iterator<?> it = jsonObject.keys();
			while (it.hasNext()) {
				String key = String.valueOf(it.next());
				Object value = jsonObject.get(key);
				if (!ToolsUtil.isBlank(value)) {
					if (value instanceof JSONArray) {
						JSONArray jsonArr = createSortArray(JSONArray.fromObject(value));
						mapTemp.put(key, jsonArr);
					} else if(value instanceof JSONObject){
						JSONObject jsonObj=createSortObject(JSONObject.fromObject(value));
						mapTemp.put(key, jsonObj);
					}else{
						mapTemp.put(key, value);
					}
				}
			}
			jsonList.add(JSONObject.fromObject(mapTemp).toString());
		}
		Collections.sort(jsonList);
		// System.out.println("json排序内容======="+JSONArray.fromObject(jsonList));
		return JSONArray.fromObject(jsonList);
	}


	/**
	 * json对象排序
	 *
	 * @param jsonArray
	 * @return
	 */
	private static JSONObject createSortObject(JSONObject jsonObject) {
		Map<String, Object> mapTemp = new TreeMap<String, Object>();
		Iterator<?> it = jsonObject.keys();
		while (it.hasNext()) {
			String key = String.valueOf(it.next());
			Object value = jsonObject.get(key);
			if (!ToolsUtil.isBlank(value)) {
				if (value instanceof JSONArray) {
					JSONArray jsonArray = createSortArray(JSONArray.fromObject(value));
					mapTemp.put(key, jsonArray);
				} else if(value instanceof JSONObject){
					JSONObject jsonObj=createSortObject(JSONObject.fromObject(value));
					mapTemp.put(key, jsonObj);
				}else{
					mapTemp.put(key, value);
				}
			}
		}
		//System.out.println("json排序内容======="+JSONObject.fromObject(mapTemp));
		return JSONObject.fromObject(mapTemp);
	}

	/**
	 * 字典序排序
	 *
	 * @param mapTmp
	 * @param signKey
	 * @return
	 */
	@SuppressWarnings(value = { "all" })
	private static String genString(Map<String, Object> mapTmp, String keyStr,KeyType keyType) {
		ArrayList arrayTmp = new ArrayList();
		for (Map.Entry entry : mapTmp.entrySet()) {
			String strValue = entry.getValue().toString();
			if (!ToolsUtil.isBlank(strValue)) {
				arrayTmp.add((String) entry.getKey() + "=" + entry.getValue() + "&");
			}
		}

		String[] strArray = (String[]) arrayTmp.toArray(new String[arrayTmp.size()]);
		Arrays.sort(strArray);
		StringBuffer strBuf = new StringBuffer();
		for (int i = 0; i < strArray.length; i++) {
			strBuf.append(strArray[i]);
		}
		strBuf.deleteCharAt(strBuf.length() - 1);
		strBuf.append(keyType.getBlock());
		strBuf.append(keyStr);
		return strBuf.toString();
	}

	/**
	 * MD5签名
	 *
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	private static String calcValidateSign(String strValue) throws UnsupportedEncodingException {
		byte[] byteString = strValue.getBytes("UTF-8");
		byte[] result;
		try {
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			mdInst.update(byteString);
			result = mdInst.digest();
		} catch (NoSuchAlgorithmException e) {
			return null;
		}
		return binaryToHexString(result).toUpperCase();
	}

	/**
	 * MD5二进制转换为16进制字符串
	 *
	 * @param ib
	 * @return
	 */
	private static String binaryToHexString(byte[] result) {
		StringBuffer digestHexStr = new StringBuffer();
		for (int i = 0; i < 16; i++) {
			char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
			char[] ob = new char[2];
			ob[0] = Digit[(result[i] >>> 4) & 0X0F];
			ob[1] = Digit[result[i] & 0X0F];
			String s = new String(ob);
			digestHexStr.append(s);
		}
		return digestHexStr.toString();
	}
}
